home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / The World of Computer Software.iso / srcuc.zip / UXCTTY.C < prev    next >
C/C++ Source or Header  |  1992-05-05  |  16KB  |  566 lines

  1. /* -*-C-*-
  2.  
  3. $Header: /scheme/src/microcode/RCS/uxctty.c,v 1.11 1992/05/05 06:37:40 jinx Exp $
  4.  
  5. Copyright (c) 1990-1992 Massachusetts Institute of Technology
  6.  
  7. This material was developed by the Scheme project at the Massachusetts
  8. Institute of Technology, Department of Electrical Engineering and
  9. Computer Science.  Permission to copy this software, to redistribute
  10. it, and to use it for any purpose is granted, subject to the following
  11. restrictions and understandings.
  12.  
  13. 1. Any copy made of this software must include this copyright notice
  14. in full.
  15.  
  16. 2. Users of this software agree to make their best efforts (a) to
  17. return to the MIT Scheme project any improvements or extensions that
  18. they make, so that these may be included in future releases; and (b)
  19. to inform MIT of noteworthy uses of this software.
  20.  
  21. 3. All materials developed as a consequence of the use of this
  22. software shall duly acknowledge such use, in accordance with the usual
  23. standards of acknowledging credit in academic research.
  24.  
  25. 4. MIT has made no warrantee or representation that the operation of
  26. this software will be error-free, and MIT is under no obligation to
  27. provide any services, by way of maintenance, update, or otherwise.
  28.  
  29. 5. In conjunction with products arising from the use of this material,
  30. there shall be no use of the name of the Massachusetts Institute of
  31. Technology nor of any adaptation thereof in any advertising,
  32. promotional, or sales literature without prior written consent from
  33. MIT in each case. */
  34.  
  35. #include "ux.h"
  36. #include "osctty.h"
  37. #include "ossig.h"
  38.  
  39. /* If `ctty_fildes' is nonnegative, it is an open file descriptor for
  40.    the controlling terminal of the process.
  41.  
  42.    If `ctty_fildes' is negative, Scheme should not alter the control
  43.    terminal's settings. */
  44. static int ctty_fildes;
  45.  
  46. /* This flag says whether Scheme was in the foreground when it was
  47.    last entered.  Provided that no other process forces Scheme out of
  48.    the foreground, it will remain in the foreground until it exits or
  49.    is stopped.
  50.  
  51.    If `scheme_in_foreground' is zero, Scheme should not alter the
  52.    control terminal's settings, nor should it alter the settings of
  53.    stdin, stdout, or stderr if they are terminals. */
  54. int scheme_in_foreground;
  55.  
  56. /* This flag, set during initialization, says whether we are
  57.    permitted to change the settings of the control terminal. */
  58. static int permit_ctty_control;
  59.  
  60. /* Original states of the control terminal, stdin, and stdout when
  61.    Scheme was last continued or stopped, respectively.  If the
  62.    corresponding `_recorded' flag is zero, then no information is
  63.    saved. */
  64.  
  65. struct terminal_state_recording
  66. {
  67.   int fd;
  68.   int recorded_p;
  69.   Ttty_state state;
  70.   int flags;
  71. };
  72.  
  73. static struct terminal_state_recording outside_ctty_state;
  74. static struct terminal_state_recording outside_stdin_state;
  75. static struct terminal_state_recording outside_stdout_state;
  76. static struct terminal_state_recording inside_ctty_state;
  77. static struct terminal_state_recording inside_stdin_state;
  78. static struct terminal_state_recording inside_stdout_state;
  79.  
  80. static void EXFUN (ctty_update_interrupt_chars, (void));
  81.  
  82. static int
  83. DEFUN (get_terminal_state, (fd, s), int fd AND Ttty_state * s)
  84. {
  85.   while (1)
  86.     {
  87.       int scr = (UX_terminal_get_state (fd, s));
  88.       if ((scr >= 0) || (errno != EINTR))
  89.     return (scr);
  90.     }
  91. }
  92.  
  93. static int
  94. DEFUN (set_terminal_state, (fd, s), int fd AND Ttty_state * s)
  95. {
  96.   while (1)
  97.     {
  98.       int scr = (UX_terminal_set_state (fd, s));
  99.       if ((scr >= 0) || (errno != EINTR))
  100.     return (scr);
  101.     }
  102. }
  103.  
  104.  
  105. static int
  106. DEFUN (get_flags, (fd, flags), int fd AND int * flags)
  107. {
  108. #ifdef FCNTL_NONBLOCK
  109.   while (1)
  110.     {
  111.       int scr = (UX_fcntl (fd, F_GETFL, 0));
  112.       if (scr >= 0)
  113.     {
  114.       (*flags) = scr;
  115.       return (0);
  116.     }
  117.       if (errno != EINTR)
  118.     return (-1);
  119.     }
  120. #else
  121.   return (0);
  122. #endif
  123. }
  124.  
  125. static int
  126. DEFUN (set_flags, (fd, flags), int fd AND int * flags)
  127. {
  128. #ifdef FCNTL_NONBLOCK
  129.   while (1)
  130.     {
  131.       int scr = (UX_fcntl (fd, F_SETFL, (*flags)));
  132.       if ((scr >= 0) || (errno != EINTR))
  133.     return (scr);
  134.     }
  135. #else
  136.   return (0);
  137. #endif
  138. }
  139.  
  140. static void
  141. DEFUN (save_external_state, (s), struct terminal_state_recording * s)
  142. {
  143.   (s -> recorded_p) =
  144.     (scheme_in_foreground
  145.      && (isatty (s -> fd))
  146.      && ((get_terminal_state ((s -> fd), (& (s -> state)))) >= 0)
  147.      && ((get_flags ((s -> fd), (& (s -> flags)))) >= 0));
  148. }
  149.  
  150. static void
  151. DEFUN (restore_external_state, (s), struct terminal_state_recording * s)
  152. {
  153.   if (s -> recorded_p)
  154.     {
  155.       set_terminal_state ((s -> fd), (& (s -> state)));
  156.       set_flags ((s -> fd), (& (s -> flags)));
  157.       (s -> recorded_p) = 0;
  158.     }
  159. }
  160.  
  161. void
  162. DEFUN (save_internal_state, (s, es),
  163.        struct terminal_state_recording * s AND
  164.        struct terminal_state_recording * es)
  165. {
  166.   /* Don't do anything unless we have a recording of the external
  167.      state.  Otherwise, we should preserve the previous recording of
  168.      the internal state, if any. */
  169.   if (es -> recorded_p)
  170.     (s -> recorded_p) =
  171.       (((get_terminal_state ((s -> fd), (& (s -> state)))) >= 0)
  172.        && ((get_flags ((s -> fd), (& (s -> flags)))) >= 0));
  173. }
  174.  
  175. static void
  176. DEFUN (restore_internal_state, (s, es),
  177.        struct terminal_state_recording * s AND
  178.        struct terminal_state_recording * es)
  179. {
  180.   /* When we recorded the internal state, we had a recording of the
  181.      external state.  But since we've stopped Scheme and restarted it,
  182.      we may no longer have a current recording of the external state.
  183.      If we don't, then we can't restore the internal state.
  184.  
  185.      The usual reason that we don't have a recording is that Scheme is
  186.      in the background.  In that case it would be nice to preserve the
  187.      previous internal state until we go back to the foreground.  But
  188.      doing that transparently would also require tracking all
  189.      attempted state changes in the recording, which is a pain.  So if
  190.      we can't restore the internal state, we just thrown it away. */
  191.   if (s -> recorded_p)
  192.     {
  193.       if (es -> recorded_p)
  194.     {
  195.       set_terminal_state ((s -> fd), (& (s -> state)));
  196.       set_flags ((s -> fd), (& (s -> flags)));
  197.     }
  198.       (s -> recorded_p) = 0;
  199.     }
  200. }
  201.  
  202. void
  203. DEFUN_VOID (UX_ctty_save_external_state)
  204. {
  205.   if (permit_ctty_control && (ctty_fildes >= 0))
  206.     {
  207.       pid_t pgrp_id = (UX_tcgetpgrp (ctty_fildes));
  208.       scheme_in_foreground =
  209.     ((pgrp_id < 0)
  210.      /* If no job control, assume we're in foreground. */
  211.      ? (errno == ENOSYS)
  212.      : ((UX_getpgrp ()) == pgrp_id));
  213.     }
  214.   else
  215.     scheme_in_foreground = 0;
  216.   save_external_state (&outside_ctty_state);
  217.   save_external_state (&outside_stdin_state);
  218.   save_external_state (&outside_stdout_state);
  219. }
  220.  
  221. void
  222. DEFUN_VOID (UX_ctty_restore_external_state)
  223. {
  224.   restore_external_state (&outside_ctty_state);
  225.   restore_external_state (&outside_stdin_state);
  226.   restore_external_state (&outside_stdout_state);
  227. }
  228.  
  229. void
  230. DEFUN_VOID (UX_ctty_save_internal_state)
  231. {
  232.   save_internal_state ((&inside_ctty_state), (&outside_ctty_state));
  233.   save_internal_state ((&inside_stdin_state), (&outside_stdin_state));
  234.   save_internal_state ((&inside_stdout_state), (&outside_stdout_state));
  235. }
  236.  
  237. void
  238. DEFUN_VOID (UX_ctty_restore_internal_state)
  239. {
  240.   int do_update =
  241.     ((inside_ctty_state . recorded_p)
  242.      && (outside_ctty_state . recorded_p));
  243.   restore_internal_state ((&inside_ctty_state), (&outside_ctty_state));
  244.   restore_internal_state ((&inside_stdin_state), (&outside_stdin_state));
  245.   restore_internal_state ((&inside_stdout_state), (&outside_stdout_state));
  246.   if (do_update)
  247.     ctty_update_interrupt_chars ();
  248. }
  249.  
  250. int
  251. DEFUN_VOID (OS_ctty_interrupt_control)
  252. {
  253.   return (outside_ctty_state . recorded_p);
  254. }
  255.  
  256. int
  257. DEFUN (UX_terminal_control_ok, (fd), int fd)
  258. {
  259.   return
  260.     ((fd == STDIN_FILENO)
  261.      ? (outside_stdin_state . recorded_p)
  262.      : (fd == STDOUT_FILENO)
  263.      ? (outside_stdout_state . recorded_p)
  264.      : 1);
  265. }
  266.  
  267. /* Keyboard Interrupt Characters */
  268.  
  269. typedef struct
  270. {
  271.   cc_t quit;
  272.   cc_t intrpt;
  273.   cc_t tstp;
  274.   cc_t dtstp;
  275. } Tinterrupt_chars;
  276.  
  277. static Tinterrupt_enables current_interrupt_enables;
  278. static Tinterrupt_chars current_interrupt_chars;
  279.  
  280. #define DEFAULT_SIGQUIT_CHAR    ((cc_t) '\003') /* ^C */
  281. #define DEFAULT_SIGINT_CHAR    ((cc_t) '\007') /* ^G */
  282. #define DEFAULT_SIGTSTP_CHAR    ((cc_t) '\032') /* ^Z */
  283.  
  284. #define KEYBOARD_QUIT_INTERRUPT        0x1
  285. #define KEYBOARD_INTRPT_INTERRUPT    0x2
  286. #define KEYBOARD_TSTP_INTERRUPT        0x4
  287. #define KEYBOARD_ALL_INTERRUPTS        0x7
  288.  
  289. cc_t
  290. DEFUN_VOID (OS_ctty_quit_char)
  291. {
  292.   return (current_interrupt_chars . quit);
  293. }
  294.  
  295. cc_t
  296. DEFUN_VOID (OS_ctty_int_char)
  297. {
  298.   return (current_interrupt_chars . intrpt);
  299. }
  300.  
  301. cc_t
  302. DEFUN_VOID (OS_ctty_tstp_char)
  303. {
  304.   return (current_interrupt_chars . tstp);
  305. }
  306.  
  307. cc_t
  308. DEFUN_VOID (OS_ctty_disabled_char)
  309. {
  310.   return ((ctty_fildes >= 0) ? (UX_PC_VDISABLE (ctty_fildes)) : '\377');
  311. }
  312.  
  313. int
  314. DEFUN_VOID (OS_ctty_fd)
  315. {
  316.   return (ctty_fildes);
  317. }
  318.  
  319. #if 0
  320.  
  321. /* not currently used */
  322. static void
  323. DEFUN (ctty_get_interrupt_chars, (ic), Tinterrupt_chars * ic)
  324. {
  325.   Ttty_state s;
  326.   if ((get_terminal_state (ctty_fildes, (&s))) == 0)
  327.     {
  328. #ifdef HAVE_TERMIOS
  329.       (ic -> quit) = ((s . tio . c_cc) [VQUIT]);
  330.       (ic -> intrpt) = ((s . tio . c_cc) [VINTR]);
  331.       (ic -> tstp) = ((s . tio . c_cc) [VSUSP]);
  332.  
  333. #ifdef VDSUSP
  334.       (ic -> dtstp) = ((s . tio . c_cc) [VDSUSP]);
  335. #else /* not VDSUSP */
  336. #ifdef _HPUX
  337.       (ic -> dtstp) = (s . ltc . t_dsuspc);
  338. #endif /* _HPUX */
  339. #endif /* not VDSUSP */
  340.  
  341. #else /* not HAVE_TERMIOS */
  342. #ifdef HAVE_TERMIO
  343.  
  344.       (ic -> quit) = ((s . tio . c_cc) [VQUIT]);
  345.       (ic -> intrpt) = ((s . tio . c_cc) [VINTR]);
  346. #ifdef HAVE_BSD_JOB_CONTROL
  347.       (ic -> tstp) = (s . ltc . t_suspc);
  348.       (ic -> dtstp) = (s . ltc . t_dsuspc);
  349. #else /* not HAVE_BSD_JOB_CONTROL */
  350.       {
  351.     cc_t disabled_char = (UX_PC_VDISABLE (ctty_fildes));
  352.     (ic -> tstp) = disabled_char;
  353.     (ic -> dtstp) = disabled_char;
  354.       }
  355. #endif /* not HAVE_BSD_JOB_CONTROL */
  356.  
  357. #else /* not HAVE_TERMIO */
  358. #ifdef HAVE_BSD_TTY_DRIVER
  359.  
  360.       (ic -> quit) = (s . tc . t_quitc);
  361.       (ic -> intrpt) = (s . tc . t_intrc);
  362. #ifdef HAVE_BSD_JOB_CONTROL
  363.       (ic -> tstp) = (s . ltc . t_suspc);
  364.       (ic -> dtstp) = (s . ltc . t_dsuspc);
  365. #else /* not HAVE_BSD_JOB_CONTROL */
  366.       {
  367.     cc_t disabled_char = (UX_PC_VDISABLE (ctty_fildes));
  368.     (ic -> tstp) = disabled_char;
  369.     (ic -> dtstp) = disabled_char;
  370.       }
  371. #endif /* not HAVE_BSD_JOB_CONTROL */
  372.  
  373. #endif /* HAVE_BSD_TTY_DRIVER */
  374. #endif /* HAVE_TERMIO */
  375. #endif /* HAVE_TERMIOS */
  376.     }
  377.   else
  378.     {
  379.       cc_t disabled_char = (UX_PC_VDISABLE (ctty_fildes));
  380.       (ic -> quit) = disabled_char;
  381.       (ic -> intrpt) = disabled_char;
  382.       (ic -> tstp) = disabled_char;
  383.       (ic -> dtstp) = disabled_char;
  384.     }
  385. }
  386. #endif /* 0 */
  387.  
  388. static void
  389. DEFUN (ctty_set_interrupt_chars, (ic), Tinterrupt_chars * ic)
  390. {
  391.   Ttty_state s;
  392.   if ((get_terminal_state (ctty_fildes, (&s))) == 0)
  393.     {
  394. #ifdef HAVE_TERMIOS
  395.       ((s . tio . c_cc) [VQUIT]) = (ic -> quit);
  396.       ((s . tio . c_cc) [VINTR]) = (ic -> intrpt);
  397.       ((s . tio . c_cc) [VSUSP]) = (ic -> tstp);
  398. #ifdef VDSUSP
  399.       ((s . tio . c_cc) [VDSUSP]) = (ic -> dtstp);
  400. #else /* not VDSUSP */
  401. #ifdef _HPUX
  402.       (s . ltc . t_suspc) = (ic -> tstp);
  403.       (s . ltc . t_dsuspc) = (ic -> dtstp);
  404. #endif /* _HPUX */
  405. #endif /* not VDSUSP */
  406.  
  407. #else /* not HAVE_TERMIOS */
  408. #ifdef HAVE_TERMIO
  409.  
  410.       ((s . tio . c_cc) [VQUIT]) = (ic -> quit);
  411.       ((s . tio . c_cc) [VINTR]) = (ic -> intrpt);
  412. #ifdef HAVE_BSD_JOB_CONTROL
  413.       (s . ltc . t_suspc) = (ic -> tstp);
  414.       (s . ltc . t_dsuspc) = (ic -> dtstp);
  415. #endif
  416.  
  417. #else /* not HAVE_TERMIO */
  418. #ifdef HAVE_BSD_TTY_DRIVER
  419.  
  420.       (s . tc . t_quitc) = (ic -> quit);
  421.       (s . tc . t_intrc) = (ic -> intrpt);
  422. #ifdef HAVE_BSD_JOB_CONTROL
  423.       (s . ltc . t_suspc) = (ic -> tstp);
  424.       (s . ltc . t_dsuspc) = (ic -> dtstp);
  425. #endif
  426.  
  427. #endif /* HAVE_BSD_TTY_DRIVER */
  428. #endif /* HAVE_TERMIO */
  429. #endif /* HAVE_TERMIOS */
  430.       set_terminal_state (ctty_fildes, (&s));
  431.     }
  432. }
  433.  
  434. static void
  435. DEFUN_VOID (ctty_update_interrupt_chars)
  436. {
  437.   if (outside_ctty_state . recorded_p)
  438.     {
  439.       cc_t disabled_char = (UX_PC_VDISABLE (ctty_fildes));
  440.       /* Must split declaration and assignment because some compilers
  441.      do not permit aggregate initializers. */
  442.       Tinterrupt_chars active_interrupt_chars;
  443.       active_interrupt_chars = current_interrupt_chars;
  444.       if ((current_interrupt_enables & KEYBOARD_QUIT_INTERRUPT) == 0)
  445.     (active_interrupt_chars . quit) = disabled_char;
  446.       if ((current_interrupt_enables & KEYBOARD_INTRPT_INTERRUPT) == 0)
  447.     (active_interrupt_chars . intrpt) = disabled_char;
  448.       if ((current_interrupt_enables & KEYBOARD_TSTP_INTERRUPT) == 0)
  449.     (active_interrupt_chars . tstp) = disabled_char;
  450.       (active_interrupt_chars . dtstp) = disabled_char;
  451.       ctty_set_interrupt_chars (&active_interrupt_chars);
  452.     }
  453. }
  454.  
  455. void
  456. DEFUN (OS_ctty_get_interrupt_enables, (mask), Tinterrupt_enables * mask)
  457. {
  458.   (*mask) = current_interrupt_enables;
  459. }
  460.  
  461. void
  462. DEFUN (OS_ctty_set_interrupt_enables, (mask), Tinterrupt_enables * mask)
  463. {
  464.   current_interrupt_enables = (*mask);
  465.   ctty_update_interrupt_chars ();
  466. }
  467.  
  468. #if 0
  469.  
  470. void
  471. DEFUN (OS_ctty_set_interrupt_chars, (quit_char, int_char, tstp_char),
  472.        cc_t quit_char AND
  473.        cc_t int_char AND
  474.        cc_t tstp_char)
  475. {
  476.   (current_interrupt_chars . quit) = quit_char;
  477.   (current_interrupt_chars . intrpt) = int_char;
  478.   (current_interrupt_chars . tstp) = tstp_char;
  479.   ctty_update_interrupt_chars ();
  480. }
  481. #endif
  482.  
  483. unsigned int
  484. DEFUN_VOID (OS_ctty_num_int_chars)
  485. {
  486.   return (3);
  487. }
  488.  
  489. cc_t *
  490. DEFUN_VOID (OS_ctty_get_int_chars)
  491. {
  492.   static cc_t int_chars [3];
  493.  
  494.   int_chars[0] = current_interrupt_chars.quit;
  495.   int_chars[1] = current_interrupt_chars.intrpt;
  496.   int_chars[2] = current_interrupt_chars.tstp;
  497.   return (& int_chars [0]);
  498. }
  499.  
  500. void
  501. DEFUN (OS_ctty_set_int_chars, (int_chars), cc_t * int_chars)
  502. {
  503.   current_interrupt_chars.quit   = int_chars[0];
  504.   current_interrupt_chars.intrpt = int_chars[1];
  505.   current_interrupt_chars.tstp   = int_chars[2];
  506.   ctty_update_interrupt_chars ();
  507.   return;
  508. }
  509.  
  510. extern enum interrupt_handler EXFUN (OS_signal_quit_handler, (void));
  511. extern enum interrupt_handler EXFUN (OS_signal_int_handler, (void));
  512. extern enum interrupt_handler EXFUN (OS_signal_tstp_handler, (void));
  513. extern void EXFUN
  514.   (OS_signal_set_interrupt_handlers,
  515.    (enum interrupt_handler quit_handler,
  516.     enum interrupt_handler int_handler,
  517.     enum interrupt_handler tstp_handler));
  518.  
  519. cc_t *
  520. DEFUN_VOID (OS_ctty_get_int_char_handlers)
  521. {
  522.   static cc_t int_handlers [3];
  523.  
  524.   int_handlers[0] = ((cc_t) (OS_signal_quit_handler ()));
  525.   int_handlers[1] = ((cc_t) (OS_signal_int_handler ()));
  526.   int_handlers[2] = ((cc_t) (OS_signal_tstp_handler ()));
  527.   return (& int_handlers [0]);
  528. }
  529.  
  530. void
  531. DEFUN (OS_ctty_set_int_char_handlers, (int_handlers), cc_t * int_handlers)
  532. {
  533.   OS_signal_set_interrupt_handlers
  534.     (((enum interrupt_handler) (int_handlers [0])),
  535.      ((enum interrupt_handler) (int_handlers [1])),
  536.      ((enum interrupt_handler) (int_handlers [2])));
  537.   return;
  538. }
  539.  
  540. void
  541. DEFUN (UX_initialize_ctty, (interactive), int interactive)
  542. {
  543.   {
  544.     char * tty = (UX_ctermid (0));
  545.     ctty_fildes =
  546.       (((tty == 0) || ((tty[0]) == 0))
  547.        ? (-1)
  548.        : (UX_open (tty, O_RDWR, 0)));
  549.   }
  550.   permit_ctty_control = interactive;
  551.   (inside_ctty_state . fd) = (outside_ctty_state . fd) = ctty_fildes;
  552.   (inside_stdin_state . fd) = (outside_stdin_state . fd) = STDIN_FILENO;
  553.   (inside_stdout_state . fd) = (outside_stdout_state . fd) = STDOUT_FILENO;
  554.   UX_ctty_save_external_state ();
  555.   (inside_ctty_state . recorded_p) = 0;
  556.   (inside_stdin_state . recorded_p) = 0;
  557.   (inside_stdout_state . recorded_p) = 0;
  558.   (current_interrupt_chars . quit) = DEFAULT_SIGQUIT_CHAR;
  559.   (current_interrupt_chars . intrpt) = DEFAULT_SIGINT_CHAR;
  560.   (current_interrupt_chars . tstp) = DEFAULT_SIGTSTP_CHAR;
  561.   (current_interrupt_chars . dtstp) = (UX_PC_VDISABLE (ctty_fildes));
  562.   current_interrupt_enables = KEYBOARD_ALL_INTERRUPTS;
  563.   if (outside_ctty_state . recorded_p)
  564.     ctty_set_interrupt_chars (¤t_interrupt_chars);
  565. }
  566.